﻿using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace QQ2564874169.Core.Encryption
{
    public static class Encrypt
    {
        public static string SHA256(string value, Encoding encoding = null)
        {
            encoding = encoding ?? Encoding.UTF8;
            using (var hash = System.Security.Cryptography.SHA256.Create())
            {
                var hashBytes = hash.ComputeHash(encoding.GetBytes(value));
                return Convert.ToBase64String(hashBytes);
            }
        }

        public static string MD5(string data, Encoding encoding = null, bool len16 = false)
        {
            encoding = encoding ?? Encoding.UTF8;
            using (var md5 = new MD5CryptoServiceProvider())
            {
                var hashBytes = md5.ComputeHash(encoding.GetBytes(data));
                if (len16)
                {
                    return BitConverter.ToString(hashBytes, 4, 8).Replace("-", "").ToLower();
                }
                return Convert.ToBase64String(hashBytes);
            }
        }

        public static string SHA1(string data, Encoding encoding = null)
        {
            using (var sha = new SHA1CryptoServiceProvider())
            {
                var enc = encoding ?? Encoding.UTF8;
                var dataToHash = enc.GetBytes(data);
                var hashBytes = sha.ComputeHash(dataToHash);
                return Convert.ToBase64String(hashBytes);
            }
        }

        public static string HmacSHA1(string data, string key, Encoding encoding = null)
        {
            encoding = encoding ?? Encoding.UTF8;
            using (var hmacsha1 = new HMACSHA1 { Key = encoding.GetBytes(key) })
            {
                var hashBytes = hmacsha1.ComputeHash(encoding.GetBytes(data));
                return Convert.ToBase64String(hashBytes);
            }
        }

        public static string HmacSHA256(string data, string key)
        {
            var keybytes = Encoding.ASCII.GetBytes(key);
            using (var provider = new HMACSHA256(keybytes))
            {
                var databytes = Encoding.ASCII.GetBytes(data);
                var hashBytes = provider.ComputeHash(databytes);
                return Convert.ToBase64String(hashBytes);
            }
        }

        public static string Des(string content, string salt)
        {
            if (string.IsNullOrEmpty(salt))
                throw new ArgumentNullException(nameof(salt));

            while (salt.Length < 8)
            {
                salt += salt;
            }

            salt = salt.Substring(0, 8);
            var data = Encoding.UTF8.GetBytes(content);
            var key = Encoding.ASCII.GetBytes(salt);
            var iv = Encoding.ASCII.GetBytes(salt);
            using (var des = DES.Create())
            using (var ms = new MemoryStream())
            {
                using (var cs = new CryptoStream(ms, des.CreateEncryptor(key, iv), CryptoStreamMode.Write))
                {
                    cs.Write(data, 0, data.Length);
                    cs.FlushFinalBlock();
                    return Convert.ToBase64String(ms.ToArray());
                }
            }

        }

        public static RSAEncrypt RSA(string content, Encoding encoding = null)
        {
            encoding = encoding ?? Encoding.UTF8;
            using (var rsa = new RSACryptoServiceProvider())
            {
                var pub = rsa.ToXmlString(false);
                var pri = rsa.ToXmlString(true);
                rsa.FromXmlString(pub);
                var cipherbytes = rsa.Encrypt(encoding.GetBytes(content), false);
                return new RSAEncrypt(cipherbytes, pub, pri);
            }
        }

        public static string TripleDES(string content, string key, Encoding encoding = null)
        {
            if (string.IsNullOrEmpty(content))
                throw new ArgumentNullException(nameof(content));
            if (string.IsNullOrEmpty(key))
                throw new ArgumentNullException(nameof(key));
            while (key.Length < 24)
            {
                key += key;
            }

            key = key.Substring(0, 24);
            encoding = encoding ?? Encoding.UTF8;
            var data = encoding.GetBytes(content);
            using (var des = new TripleDESCryptoServiceProvider())
            {
                des.Key = encoding.GetBytes(key);
                des.IV = encoding.GetBytes(key.Substring(0, 8));
                des.Mode = CipherMode.CBC;
                des.Padding = PaddingMode.PKCS7;
                using (var ms = new MemoryStream())
                {
                    using (var cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(data, 0, data.Length);
                        cs.FlushFinalBlock();
                        cs.Close();
                    }

                    return Convert.ToBase64String(ms.ToArray());
                }
            }
        }

        public static string Aes(string content, string key, Encoding encoding = null)
        {
            if (string.IsNullOrEmpty(content))
                throw new ArgumentNullException(nameof(content));
            if (string.IsNullOrEmpty(key))
                throw new ArgumentNullException(nameof(key));
            while (key.Length < 32)
            {
                key += key;
            }

            key = key.Substring(0, 32);
            encoding = encoding ?? Encoding.UTF8;

            using (var aesAlg = System.Security.Cryptography.Aes.Create())
            {
                aesAlg.Key = Encoding.ASCII.GetBytes(key);
                aesAlg.IV = Encoding.ASCII.GetBytes(key.Substring(0, 16));

                var encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

                using (var msEncrypt = new MemoryStream())
                {
                    using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        using (var swEncrypt = new StreamWriter(csEncrypt, encoding))
                        {
                            swEncrypt.Write(content);
                        }

                        return Convert.ToBase64String(msEncrypt.ToArray());
                    }
                }
            }
        }

        public class RSAEncrypt
        {
            public byte[] CipherBytes { get; private set; }
            public string PublicKey { get; private set; }
            public string PrivateKey { get; private set; }

            internal RSAEncrypt(byte[] cipherbytes, string publicKey, string privateKey)
            {
                CipherBytes = cipherbytes;
                PublicKey = publicKey;
                PrivateKey = privateKey;
            }

            public string ToBase64()
            {
                return Convert.ToBase64String(CipherBytes);
            }

            public string ToHex()
            {
                return BitConverter.ToString(CipherBytes).Replace("-", "");
            }
        }
    }
}
